/**
 * msgs.c - Handle incoming server messages.
 *
 * woodpecker
 *
 * WoodPecker is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: msgs.c 139 2008-05-03 07:13:05Z dubkat $
 */

#include "conversation.h"
#include "blist.h"
#include "notify.h"
#include "util.h"
#include "debug.h"
#include "imgstore.h"
#include "request.h"
#include "privacy.h"
#include "prefs.h"

#include "pecker.h"
#include "info.h"
#include "priv.h"
#include "helpers.h"
#include "spam.h"

static char *
pecker_mask_nick(const char *mask)
{
    char *end, *buf;

    end = strchr(mask, '!');
    if(!end)
        buf = g_strdup(mask);
    else
        buf = g_strndup(mask, end - mask);

    return buf;
}

static void
pecker_chat_remove_buddy(PurpleConversation * convo, char *data[2])
{
    /**
     * FIXME: is *message ever used ???
     */
    char *message = g_strdup_printf("quit: %s", data[1]);

    if(purple_conv_chat_find_user(PURPLE_CONV_CHAT(convo), data[0]))
        purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), data[0], NULL);

    g_free(message);
}

void
pecker_msg_default(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    purple_debug(PURPLE_DEBUG_INFO, "pecker", "Unrecognized message: %s\n", args[0]);
}

void
pecker_msg_away(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);

    if(!args || !args[1] || !gc)
    {
        return;
    }

    gcom_nick_to_pecker(args[1]);
    serv_got_im(gc, args[1], args[2], PURPLE_MESSAGE_AUTO_RESP, time(NULL));
}

static void
pecker_fetch_photo_cb(PurpleUtilFetchUrlData * url_data, gpointer user_data, const gchar * url_text, gsize len, const gchar * err)
{
    if(!url_text || !user_data)
    {
        return;
    }

    struct get_info_data *d = user_data;
    struct pecker_conn *pecker = d->pecker;

    int id = purple_imgstore_add_with_id(g_memdup(url_text, len), len, NULL);
    char *imghtml = g_strdup_printf("<img id=\"%d\">", id);

    purple_debug_misc("userinfo", "img html: %s\n", imghtml);

    if(g_hash_table_lookup(pecker->info_window_needed, d->who))
    {
        purple_notify_user_info_add_pair(d->info, NULL, imghtml);
        purple_notify_userinfo(d->gc, d->who, d->info, NULL, NULL);
        g_hash_table_remove(pecker->info_window_needed, d->who);
    }
    // purple_notify_user_info_destroy(d->info);
    g_free(imghtml);
}

static void
pecker_fetch_info_cb(PurpleUtilFetchUrlData * url_data, void *user_data, const gchar * info_data, gsize len,
                     const gchar * error_message)
{
    struct get_info_data *d = user_data;
    char *picpath = NULL;
    char *picurl = NULL;
    char *match = "pictures.0.url=";

    purple_debug_misc("fetch info cb", "Starting\n");
    picpath = return_string_between(match, "\n", info_data);
    if(picpath)
        picurl = g_strdup_printf("http://www.gay.com%s", picpath);

    void *needed = g_hash_table_lookup(d->pecker->info_window_needed, d->who);

    if(picurl && g_hash_table_lookup(d->pecker->info_window_needed, d->who))
    {
        purple_debug_misc("msgs", "Picture url: %s\nNeeded? %s", picurl, ((const char *) needed));
        purple_util_fetch_url(picurl, FALSE, PECKER_USER_AGENT, FALSE, pecker_fetch_photo_cb, d);
        return;
        g_free(picurl);
        g_free(picpath);
    }

    else
    {
        g_hash_table_remove(d->pecker->info_window_needed, d->who);
        // purple_notify_user_info_destroy(d->info);

    }
}

void
pecker_msg_no_such_nick(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    /**
     * name = 701
     * from = irc.server.name
     * args[1] = the nick that wasn't found
     */

    if(!pecker || !args || !args[1])
    {
        return;
    }

    gcom_nick_to_pecker(args[1]);

    pecker_buddy_status(pecker, args[1], FALSE, NULL, FALSE);

    char *normalized = g_strdup(purple_normalize(pecker->account, args[1]));

    void *dialog;

    if((dialog = g_hash_table_lookup(pecker->info_window_needed, normalized)))
    {
        g_hash_table_remove(pecker->info_window_needed, normalized);

        PurpleNotifyUserInfo *info = purple_notify_user_info_new();
        char *hashurl = g_hash_table_lookup(pecker->confighash, "view-profile-url");

        g_return_if_fail(hashurl != NULL);
        char *proflink = g_strdup_printf("<a href='%s%s'>Check for Full Profile</a>",
                                         hashurl, args[1]);

        g_free(hashurl);
        purple_notify_user_info_add_pair(info, NULL, "No such user online.");
        purple_notify_user_info_add_pair(info, NULL, proflink);

        purple_notify_userinfo(purple_account_get_connection(pecker->account), args[1], info, NULL, NULL);

    }
    g_free(normalized);
}

void
pecker_msg_whois(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    /**
     * name = 311
     * from = irc.server.name
     * args[1] = the nick that we have information about
     */

    if(!pecker || !args || !args[1])
    {
        return;
    }

    char *nick = args[1];
    char *info = args[5];

    gcom_nick_to_pecker(nick);

    char *stats = pecker_stats_strdup(info);
    char *bio = pecker_bio_strdup(info);

    pecker_buddy_status(pecker, nick, TRUE, info, TRUE);

    char *normalized = g_strdup(purple_normalize(pecker->account, nick));


    // Update, but then release the reference. It was already opened
    // during conversation-created.
    // pecker_update_channel_member(pecker, normalized, info);
    // pecker_unreference_channel_member(pecker, normalized);

    // purple_debug_misc("pecker", "signalling info update for %s\n",
    // normalized);
    // purple_signal_emit(purple_accounts_get_handle(), "info-updated",
    // pecker->account, normalized);

    struct get_info_data *d;

    if((d = g_hash_table_lookup(pecker->info_window_needed, normalized)))
    {

        /* 
         * Over Complicated and frequently gets jumbled...
         * lets try a "simple" way :)
         * -dubkat
         */

        char *hashurl = g_strdup(g_hash_table_lookup(pecker->confighash, "view-profile-url"));

        g_return_if_fail(hashurl != NULL);

        char *proflink = g_strdup_printf("<a href='http://my.gay.com/%s'>Full Profile</a>", nick);

        d->info = purple_notify_user_info_new();
        purple_notify_user_info_add_pair(d->info, NULL, proflink);
        purple_notify_user_info_add_pair(d->info, "Stats", stats ? stats : "Not Found");
        purple_notify_user_info_add_pair(d->info, "Bio", bio ? bio : "Not Found");
        purple_notify_userinfo(d->gc, nick, d->info, NULL, d);
        purple_debug_misc("msg_whois", "Updated userinfo info\n");
        g_free(hashurl);
        g_free(proflink);

        hashurl = g_hash_table_lookup(pecker->confighash, "ohm.profile-url");
        g_return_if_fail(hashurl != NULL);
        char *infourl = g_strdup_printf("%s?pw=%s&name=%s", hashurl,
                                        pecker->chat_key, nick);

        if(infourl)
        {
            purple_debug_misc("msgs", "Fetching %s\n", infourl);
            purple_util_fetch_url(infourl, FALSE, PECKER_USER_AGENT, FALSE, pecker_fetch_info_cb, d);
        }
        else
        {
            g_hash_table_remove(pecker->info_window_needed, normalized);
            purple_notify_user_info_destroy(d->info);
        }
        g_free(hashurl);
        g_free(infourl);
    }
    g_free(normalized);
}

void
pecker_msg_login_failed(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{



    pecker_cmd_quit(pecker, "quit", NULL, NULL);

    // if (gc->inpa)
    // purple_input_remove(gc->inpa);

    // g_free(pecker->inbuf);
    // purple_debug_misc("pecker", "Login failed. closing fd %i\n",
    // pecker->fd);
    // close(pecker->fd);
    // purple_debug_misc("pecker", "Get chatkey from weblogin\n");
    // pecker_get_hash_from_weblogin(pecker->account,
    // pecker_login_with_chat_key);

}

void
pecker_msg_list(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    /**
     * If you free anything here related to the roomlist
     * be sure you test what happens when the roomlist reference
     * count goes to zero! Because it may crash purple.
     */
    if(!pecker->roomlist)
    {
        return;
    }
    /**
     * Begin result of member created room list
     */
    if(!strcmp(name, "321") && pecker->roomlist_filter == NULL)
    {
        PurpleRoomlistRoom *room;

        room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_CATEGORY, "Member Created", NULL);
        purple_roomlist_room_add(pecker->roomlist, room);
        purple_roomlist_set_in_progress(pecker->roomlist, TRUE);
        return;
    }

    /**
     * The list of member created rooms
     */
    if(!strcmp(name, "322"))
    {
        PurpleRoomlistRoom *room;
        char *field_start = NULL;
        char *field_end = NULL;
        size_t field_len = 0;
        int i = 0;

        if(!args[1])
        {
            return;
        }

        /**
         * strip leading "#_" and trailing "=1"
         */
        field_start = strchr(args[1], '_');
        field_end = strrchr(args[1], '=');

        if(!field_start || !field_end)
        {
            purple_debug_error("pecker", "Member created room list parsing error");
            return;
        }
        field_start++;
        field_end = field_end + 2;

        field_len = field_end - field_start;

        char *field_name = g_strndup(field_start, field_len);

        /**
         * replace all remaining "_" with " "
         */
        for (i = 0; field_name[i] != '\0'; i++)
        {
            if(field_name[i] == '_')
            {
                field_name[i] = ' ';
            }
        }
        /**
         * replace '=' with ':'
         */
        field_name[i - 2] = ':';

        gchar *lowercase = g_utf8_strdown(field_name, -1);
        gchar *normalized = g_utf8_normalize(lowercase, -1, G_NORMALIZE_ALL);

        g_free(lowercase);
        if(pecker->roomlist_filter == NULL || g_strstr_len(normalized, -1, pecker->roomlist_filter) != NULL)
        {

            room =
                purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, field_name, g_list_nth_data(pecker->roomlist->rooms, 0));
            purple_roomlist_room_add_field(pecker->roomlist, room, field_name);
            purple_roomlist_room_add_field(pecker->roomlist, room, args[1]);
            purple_roomlist_room_add(pecker->roomlist, room);
        }
        g_free(normalized);
        g_free(field_name);
    }

    /**
     * End result of member created room list
     * This is our trigger to add the static rooms
     */
    if(!strcmp(name, "323"))
    {
        build_roomlist_from_config(pecker->roomlist, pecker->confighash, pecker->roomlist_filter);
        if(pecker->roomlist_filter)
        {
            g_free(pecker->roomlist_filter);
            pecker->roomlist_filter = NULL;
        }
        return;
    }
}

void
pecker_msg_unknown(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *buf;

    if(!args || !args[1] || !gc)
        return;

    buf = g_strdup_printf("Unknown message '%s'", args[1]);
    purple_notify_error(gc, "Unknown message", buf, "Purple has sent a message the IRC server did not understand.");
    g_free(buf);
}

/* this is useless and causes a crash. disable it. */
/**
void
pecker_msg_names(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    char *names, *cur, *end, *tmp, *msg;
    PurpleConversation *convo;

    purple_debug_misc("names", "%s %s %s %s", name, from, args[1], args[2]);
    if(!strcmp(name, "366"))
    {
        PeckerNamelist *namelist = g_queue_peek_head(pecker->namelists);

        purple_debug_misc("names", "namelist->roomname:%s\n", namelist->roomname);
        if(namelist && !strncmp(namelist->roomname, args[1], strlen(namelist->roomname)))
        {
            purple_debug_misc("names", "*****Got all names responses for %s\n", args[1]);
            PeckerNamelist *namelist = g_queue_pop_head(pecker->namelists);

            purple_debug_misc("msgs", "should be emitting namelist-complete signal passing namelist %s\n",
                              ((const char *) namelist));
            purple_signal_emit(purple_accounts_get_handle(), "namelist-complete", pecker->account, namelist);
            return;
        }
        if(!pecker->nameconv)
            return;
        convo =
            purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, pecker->nameconv ? pecker->nameconv : args[1],
                                                  pecker->account);
        if(!convo)
        {
            purple_debug(PURPLE_DEBUG_ERROR, "pecker", "Got a NAMES list for %s, which doesn't exist\n", args[1]);
            g_string_free(pecker->names, TRUE);
            pecker->names = NULL;
            g_free(pecker->nameconv);
            pecker->nameconv = NULL;
            return;
        }

        names = cur = g_string_free(pecker->names, FALSE);
        pecker->names = NULL;
        if(pecker->nameconv)
        {
            msg = g_strdup_printf("Users on %s: %s", args[1] ? args[1] : "", names ? names : "");
            if(purple_conversation_get_type(convo) == PURPLE_CONV_TYPE_CHAT)
                purple_conv_chat_write(PURPLE_CONV_CHAT(convo), "", msg, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG,
                                       time(NULL));
            else
                purple_conv_im_write(PURPLE_CONV_IM(convo), "", msg, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
            g_free(msg);
            g_free(pecker->nameconv);
            pecker->nameconv = NULL;
        }
        else
        {
            GList *users = NULL;

            while (*cur)
            {
                end = strchr(cur, ' ');
                tmp = g_strndup(cur, end - cur);
                gcom_nick_to_pecker(tmp);
                users = g_list_prepend(users, tmp);
                cur = end;
                if(*cur)
                    cur++;
            }
            users = g_list_reverse(users);

            if(users != NULL)
            {
                GList *l;

                purple_conv_chat_add_users(PURPLE_CONV_CHAT(convo), users, NULL, NULL, FALSE);

                for (l = users; l != NULL; l = l->next)
                    g_free(l->data);

                g_list_free(users);
            }
        }
        g_free(names);
    }
    else
    {
        if(pecker->nameconv && !pecker->names)
        {
            pecker->names = g_string_new("");
            pecker->names = g_string_append(pecker->names, args[3]);
        }
        purple_debug_misc("names", "Response: %s\n", args[3]);
        PeckerNamelist *nameslist = g_queue_peek_head(pecker->namelists);

        if(nameslist)
        {
            gchar **names = g_strsplit(args[3], " ", -1);


            int i = 0;

            purple_debug_misc("names", "names[i]: %s, nameslist->current: %s\n", names[i], ((const char *) nameslist->current));
            while (names[i] && strlen(names[i]) && nameslist->current)
            {
                ((PeckerBuddy *) (nameslist->current->data))->name = g_strdup(names[i]);
                nameslist->current = g_slist_next(nameslist->current);
                i++;
            }
            g_strfreev(names);

        }
    }
}

*/

/**
 * Change this to WELCOME
 */

void
pecker_msg_endmotd(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc;

    PurpleBlistNode *gnode, *cnode, *bnode;

    purple_debug_misc("pecker", "Got motd\n");

    gc = purple_account_get_connection(pecker->account);
    if(!gc)
    {
        purple_debug_misc("pecker", "!gc ???\n");
        return;
    }
    purple_connection_set_state(gc, PURPLE_CONNECTED);
    // serv_finish_login(gc);
    /* this used to be in the core, but it's not now */
    for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next)
    {
        if(!PURPLE_BLIST_NODE_IS_GROUP(gnode))
            continue;
        for (cnode = gnode->child; cnode; cnode = cnode->next)
        {
            if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode))
                continue;
            for (bnode = cnode->child; bnode; bnode = bnode->next)
            {
                PurpleBuddy *b;

                if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
                    continue;
                b = (PurpleBuddy *) bnode;
                if(b->account == gc->account)
                {
                    struct pecker_buddy *ib = g_new0(struct pecker_buddy, 1);

                    ib->name = g_strdup(b->name);
                    g_hash_table_insert(pecker->buddies, ib->name, ib);
                }
            }
        }
    }

    purple_debug_misc("pecker", "Calling blist timeout\n");
    pecker_blist_timeout(pecker);
    if(!pecker->timer)
        pecker->timer = purple_timeout_add(BLIST_UPDATE_PERIOD, (GSourceFunc) pecker_blist_timeout, (gpointer) pecker);
}

void
pecker_msg_nochan(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);

    if(gc == NULL || args == NULL || args[1] == NULL)
        return;

    purple_notify_error(gc, NULL, "No such channel", args[1]);
}

void
pecker_msg_nonick_chan(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    PurpleConversation *convo;

    convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, args[1], pecker->account);
    if(convo)
    {
        if(purple_conversation_get_type(convo) == PURPLE_CONV_TYPE_CHAT)
        {
            /* does this happen? */
            purple_conv_chat_write(PURPLE_CONV_CHAT(convo), args[1], "no such channel",
                                   PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
        }
        else
        {
            purple_conv_im_write(PURPLE_CONV_IM(convo), args[1], "User is not logged in",
                                 PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
        }
    }
    else
    {
        if((gc = purple_account_get_connection(pecker->account)) == NULL)
            return;
        purple_notify_error(gc, NULL, "Not logged in: ", args[1]);
    }

    if(gc == NULL || args == NULL || args[1] == NULL)
        return;


}

void
pecker_msg_nonick(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc;
    PurpleConversation *convo;

    convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, args[1], pecker->account);
    if(convo)
    {
        if(purple_conversation_get_type(convo) == PURPLE_CONV_TYPE_CHAT)
        {
            /* does this happen? */
            purple_conv_chat_write(PURPLE_CONV_CHAT(convo), args[1], "no such channel",
                                   PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
        }
        else
        {
            purple_conv_im_write(PURPLE_CONV_IM(convo), args[1], "User is not logged in",
                                 PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
        }
    }
    else
    {
        if((gc = purple_account_get_connection(pecker->account)) == NULL)
            return;
        purple_notify_error(gc, NULL, "No such nick or channel", args[1]);
    }
}

void
pecker_msg_nosend(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc;
    PurpleConversation *convo;

    convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], pecker->account);
    if(convo)
    {
        purple_conv_chat_write(PURPLE_CONV_CHAT(convo), args[1], args[2], PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG,
                               time(NULL));
    }
    else
    {
        if((gc = purple_account_get_connection(pecker->account)) == NULL)
            return;
        purple_notify_error(gc, NULL, "Could not send", args[2]);
    }
}

/**
 * Is this used?
 */
void
pecker_msg_notinchan(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConversation *convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
                                                                      args[1],
                                                                      pecker->account);

    purple_debug(PURPLE_DEBUG_INFO, "pecker", "We're apparently not in %s, but tried to use it\n", args[1]);
    if(convo)
    {
        /* g_slist_remove(pecker->gc->buddy_chats, convo); purple_conversation_set_account(convo,
           NULL); */
        purple_conv_chat_write(PURPLE_CONV_CHAT(convo), args[1], args[2], PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG,
                               time(NULL));
    }
}

/**
 * Invite WORKS in gay.com! (since when? -dub)
 */
void
pecker_msg_invite(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *nick = pecker_mask_nick(from);
    GHashTable *components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);

    if(!args || !args[1] || !gc)
    {
        g_free(nick);
        g_hash_table_destroy(components);
        return;
    }

    if(!pecker_privacy_check(gc, nick))
    {
        g_free(nick);
        g_hash_table_destroy(components);
        return;
    }

    g_hash_table_insert(components, strdup("channel"), strdup(args[1]));
    gcom_nick_to_pecker(nick);
    serv_got_chat_invite(gc, args[1], nick, NULL, components);

    g_free(nick);
}

void
pecker_msg_inviteonly(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *buf;

    if(!args || !args[1] || !gc)
        return;

    buf = g_strdup_printf("Joining %s requires an invitation.", args[1]);
    purple_notify_error(gc, "Invitation only", "Invitation only", buf);
    g_free(buf);
}

void
pecker_msg_trace(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY,
                                                                     pecker->traceconv ? pecker->traceconv : args[1],
                                                                     pecker->account);

    purple_conversation_write(conv, "TRACE", args[3], PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));

}

void
pecker_msg_join(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    purple_debug_misc("join", "got join for %s\n", args[0]);
    PurpleConnection *gc = purple_account_get_connection(pecker->account);

    g_return_if_fail(gc != NULL);

    char *nick = pecker_mask_nick(from);

    PurpleConversation *convo;
    PurpleConvChatBuddyFlags flags = PURPLE_CBFLAGS_NONE;
    char *bio = NULL;
    static int id = 1;

    gcom_nick_to_pecker(nick);
    if(!purple_utf8_strcasecmp(nick, purple_connection_get_display_name(gc)))
    {
        /* We are joining a channel for the first time */

        gpointer data, unused;
        gboolean hammering = g_hash_table_lookup_extended(pecker->hammers, args[0], &unused, &data);

        // There was a hammer, but it is cancelled. Leave!
        purple_debug_misc("join", "Joined %s\n", args[0]);
        if(hammering && !data)
        {                       // hammer was cancelled.
            purple_debug_misc("pecker", "JOINED, BUT HAMMER CANCELLED: ABORT!!!!\n");
            g_hash_table_remove(pecker->hammers, args[0]);
            pecker_cmd_part(pecker, NULL, NULL, (const char **) args);
            return;
        }

        g_hash_table_remove(pecker->hammers, args[0]);
        serv_got_joined_chat(gc, id++, args[0]);

        gint *entry = g_new(gint, 1);

        *entry = MAX_CHANNEL_MEMBERS;
        g_hash_table_insert(pecker->entry_order, g_strdup(args[0]), entry);

        g_free(nick);
        return;
    }

    convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, args[0], pecker->account);
    if(convo == NULL)
    {
        purple_debug(PURPLE_DEBUG_ERROR, "pecker", "JOIN for %s failed\n", args[0]);
        g_free(nick);
        return;
    }

    gint *entry = g_hash_table_lookup(pecker->entry_order, args[0]);

    g_return_if_fail(entry != NULL);

    pecker_buddy_status(pecker, nick, TRUE, args[1], TRUE);

    if(purple_prefs_get_bool("/plugins/prpl/pecker/show_bio_with_join"))
        bio = pecker_bio_strdup(args[1]);

    /* ugly hack to prevent a bracket being apart of a [http] link. */
    if(bio)
        bio = g_strdup_printf(" %s ", bio);


    if(*entry <= MAX_CHANNEL_MEMBERS)
    {
        *entry = MAX_CHANNEL_MEMBERS + 1;
    }

    flags = chat_pecking_order(args[1]);
    flags = include_chat_entry_order(flags, (*entry)++);

    gboolean pecker_privacy_permit = pecker_privacy_check(gc, nick);
    gboolean show_join = purple_prefs_get_bool("/plugins/prpl/pecker/show_join");

    purple_conv_chat_add_user(PURPLE_CONV_CHAT(convo), nick, bio, flags, (pecker_privacy_permit && show_join));


    /**
     * Make the ignore.png icon appear next to the nick.
     */
    PurpleConversationUiOps *ops = purple_conversation_get_ui_ops(convo);

    if(pecker_privacy_permit)
    {
        purple_conv_chat_unignore(PURPLE_CONV_CHAT(convo), nick);
    }
    else
    {
        purple_conv_chat_ignore(PURPLE_CONV_CHAT(convo), nick);
    }
    ops->chat_update_user((convo), nick);

    pecker_update_channel_member(pecker, nick, args[1]);
    g_free(bio);
    g_free(nick);
}

void
pecker_msg_mode(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConversation *convo;
    char *nick = pecker_mask_nick(from), *buf;

    if(*args[0] == '#' || *args[0] == '&')
    {                           /* Channel */
        convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, args[0], pecker->account);
        if(!convo)
        {
            purple_debug(PURPLE_DEBUG_ERROR, "pecker", "MODE received for %s, which we are not in\n", args[0]);
            g_free(nick);
            return;
        }
        buf = g_strdup_printf("mode (%s %s) by %s", args[1], args[2] ? args[2] : "", nick);
        purple_conv_chat_write(PURPLE_CONV_CHAT(convo), args[0], buf, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
        g_free(buf);
        if(args[2])
        {
            PurpleConvChatBuddyFlags newflag, flags;
            char *mcur, *cur, *end, *user;
            gboolean add = FALSE;

            mcur = args[1];
            cur = args[2];
            while (*cur && *mcur)
            {
                if((*mcur == '+') || (*mcur == '-'))
                {
                    add = (*mcur == '+') ? TRUE : FALSE;
                    mcur++;
                    continue;
                }
                end = strchr(cur, ' ');
                if(!end)
                    end = cur + strlen(cur);
                user = g_strndup(cur, end - cur);
                flags = purple_conv_chat_user_get_flags(PURPLE_CONV_CHAT(convo), user);
                newflag = PURPLE_CBFLAGS_NONE;
                if(*mcur == 'o')
                    newflag = PURPLE_CBFLAGS_OP;
                else if(*mcur == 'h')
                    newflag = PURPLE_CBFLAGS_HALFOP;
                else if(*mcur == 'v')
                    newflag = PURPLE_CBFLAGS_VOICE;
                if(newflag)
                {
                    if(add)
                        flags |= newflag;
                    else
                        flags &= ~newflag;
                    purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(convo), user, flags);
                }
                g_free(user);
                cur = end;
                if(*cur)
                    cur++;
                if(*mcur)
                    mcur++;
            }
        }
    }
    else
    {                           /* User */
    }
    g_free(nick);
}

void
pecker_msg_nick(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    GSList *chats;

    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *nick = pecker_mask_nick(from);

    if(!gc)
    {
        g_free(nick);
        return;
    }

    chats = gc->buddy_chats;

    if(!purple_utf8_strcasecmp(nick, purple_connection_get_display_name(gc)))
    {
        purple_connection_set_display_name(gc, args[0]);
    }

    while (chats)
    {
        PurpleConvChat *chat = PURPLE_CONV_CHAT(chats->data);

        /* This is ugly ... */
        if(purple_conv_chat_find_user(chat, nick))
            purple_conv_chat_rename_user(chat, nick, args[0]);
        chats = chats->next;
    }
    g_free(nick);
}

void
pecker_msg_notice(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);

    if(!gc)
    {
        return;
    }

    char *newargs[2];

    newargs[0] = " notice ";    /* The spaces are magic, leave 'em in! */
    newargs[1] = args[1];
    pecker_msg_privmsg(pecker, name, from, newargs);
}

void
pecker_msg_part(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConversation *convo;
    char *msg;

    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *nick = pecker_mask_nick(from);

    if(!args || !args[0] || !gc || !nick)
    {
        g_free(nick);
        return;
    }

    convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, args[0], pecker->account);
    gboolean show_part = purple_prefs_get_bool("/plugins/prpl/pecker/show_part");

    gcom_nick_to_pecker(nick);
    if(!purple_utf8_strcasecmp(nick, purple_connection_get_display_name(gc)))
    {

        g_hash_table_remove(pecker->entry_order, args[0]);
        msg = g_strdup_printf("You have parted the channel");

        purple_conv_chat_write(PURPLE_CONV_CHAT(convo), args[0], msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
        g_free(msg);
        serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)));
    }
    else
    {
        if(!purple_conv_chat_is_user_ignored(PURPLE_CONV_CHAT(convo), nick) && show_part)
        {
            purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), nick, NULL);
        }
        else
        {
            PurpleConversationUiOps *ops = purple_conversation_get_ui_ops(convo);

            if(ops != NULL && ops->chat_remove_users != NULL)
            {
                GList *users = g_list_append(NULL, (char *) nick);

                ops->chat_remove_users(convo, users);
            }
            PurpleConvChatBuddy *cb = purple_conv_chat_cb_find(PURPLE_CONV_CHAT(convo), nick);

            if(cb)
            {
                purple_conv_chat_set_users(PURPLE_CONV_CHAT(convo),
                                           g_list_remove(purple_conv_chat_get_users(PURPLE_CONV_CHAT(convo)), cb));
                purple_conv_chat_cb_destroy(cb);
                if(!pecker_unreference_channel_member(pecker, nick))
                    purple_debug_error("pecker", "channel_members reference counting bug.\n");
            }
        }
    }

    g_free(nick);
}

void
pecker_msg_ping(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    char *buf;

    if(!args || !args[0])
        return;

    buf = pecker_format(pecker, "v:", "PONG", args[0]);
    pecker_send(pecker, buf);
    g_free(buf);
}

void
pecker_msg_pong(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConversation *convo;
    PurpleConnection *gc;
    char **parts, *msg;
    time_t oldstamp;

    if(!args || !args[1])
        return;

    parts = g_strsplit(args[1], " ", 2);

    if(!parts[0] || !parts[1])
    {
        g_strfreev(parts);
        return;
    }

    if(sscanf(parts[1], "%lu", &oldstamp) != 1)
    {
        msg = g_strdup("Error: invalid PONG from server");
    }
    else
    {
        msg = g_strdup_printf("PING reply -- Lag: %lu seconds", time(NULL) - oldstamp);
    }

    convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, parts[0], pecker->account);
    g_strfreev(parts);
    if(convo)
    {
        if(purple_conversation_get_type(convo) == PURPLE_CONV_TYPE_CHAT)
            purple_conv_chat_write(PURPLE_CONV_CHAT(convo), "PONG", msg, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG,
                                   time(NULL));
        else
            purple_conv_im_write(PURPLE_CONV_IM(convo), "PONG", msg, PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NO_LOG, time(NULL));
    }
    else
    {
        gc = purple_account_get_connection(pecker->account);
        if(!gc)
        {
            g_free(msg);
            return;
        }
        purple_notify_info(gc, NULL, "PONG", msg);
    }
    g_free(msg);
}

void
pecker_msg_privmsg(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConversation *convo;
    char *tmp = NULL;
    char *msg = NULL;
    int notice = 0;

    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *nick = pecker_mask_nick(from);

    if(!args || !args[0] || !args[1] || !gc)
    {
        g_free(nick);
        return;
    }

    /**
     * Only nicks (sender/receiver) should use gcom_nick_to_pecker().
     *
     * Channels (which begin with either "#" or "&") should not be
     * converted.
     *
     * Messages should also not be converted.
     *
     * CHAT ROOM:
     * nick = the sender
     * args[0] = the receiving channel
     * args[1] = the message
     *
     * INSTANT MESSAGE:
     * nick = the sender
     * args[0] = the receiver (me)
     * args[1] = the message
     *
     * NOTICE:
     * nick = the sender
     * args[0] = " notice "
     * args[1] = the message
     */
    gcom_nick_to_pecker(nick);
    if(args[0][0] != '#' && args[0][0] != '&')
    {
        gcom_nick_to_pecker(args[0]);
    }

    convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, args[0], pecker->account);

    notice = !strcmp(args[0], " notice ");
    tmp = pecker_parse_ctcp(pecker, nick, args[0], args[1], notice);

    if(!tmp)
    {
        g_free(nick);
        return;
    }

    if(!pecker_privacy_check(gc, nick))
    {
        g_free(tmp);
        g_free(nick);
        return;
    }

    // msg = g_markup_escape_text(tmp, -1);
    // g_free(tmp);
    msg = tmp;

    if(notice)
    {
        tmp = g_strdup_printf("(notice) %s", msg);
        g_free(msg);
        msg = tmp;
    }

    if(!purple_utf8_strcasecmp(args[0], purple_connection_get_display_name(gc)))
    {
        serv_got_im(gc, nick, msg, 0, time(NULL));
    }
    else if(notice)
    {
        serv_got_im(gc, nick, msg, 0, time(NULL));
    }
    else if(convo)
    {
        /* hack until we obey PURPLE_MESSAGE_INVISIBLE */
        if(pecker_msg_is_spam(msg))
        {
            purple_debug_misc("pecker", "*** Ignoring message from %s due to hard-coded spam: %s \n", nick, msg);
            g_free(msg);
            g_free(nick);
            return;
        }

        serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), nick, PURPLE_MESSAGE_RECV, msg, time(NULL));
    }
    else
    {
        purple_debug(PURPLE_DEBUG_ERROR, "pecker", "Got a PRIVMSG on %s, which does not exist\n", args[0]);
    }

    g_free(msg);
    g_free(nick);
}

void
pecker_msg_regonly(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *msg;

    if(!args || !args[1] || !args[2] || !gc)
        return;

    msg = g_strdup_printf("Cannot join %s:", args[1]);
    purple_notify_error(gc, "Cannot join channel", msg, args[2]);
    g_free(msg);
}

/* I don't think gay.com ever sends this message */
void
pecker_msg_quit(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *data[2];

    if(!args || !args[0] || !gc)
        return;

    data[0] = pecker_mask_nick(from);
    data[1] = args[0];
    /* XXX this should have an API, I shouldn't grab this directly */
    g_slist_foreach(gc->buddy_chats, (GFunc) pecker_chat_remove_buddy, data);

    pecker_buddy_status(pecker, data[0], FALSE, NULL, FALSE);

    g_free(data[0]);

    return;
}

/* this isn't even used, except for using the roombrowser, which is broken.
 * so for now, i am disabling it.
 */

/**
void
pecker_msg_who(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    char *pos;
    PeckerNamelist *nameslist;

    if(!strncmp(name, "315", 3))
    {

        nameslist = g_queue_peek_head(pecker->namelists);
        if(!nameslist)
            return;
        nameslist->members = g_slist_reverse(nameslist->members);
        nameslist->current = nameslist->members;

        // If we are doing an "umbrella room" then we send out this names
        // thing.
        // Because the names parsing section terminates on a "names" from 
        // The exact channel name match.
        if(g_str_has_suffix(args[1], "=*"))
        {
            purple_debug_misc("who", "Has a =* suffix, sending out one more namescmd \n");
            const char *cmdargs[1] = { args[1] };
            pecker_cmd_names(pecker, NULL, NULL, cmdargs);
        }
        return;
    }

    if(args[2])
    {

        nameslist = g_queue_peek_tail(pecker->namelists);
        if(!nameslist)
            return;
        PeckerBuddy *member = g_new0(PeckerBuddy, 1);
        gchar **parts = g_strsplit(args[2], " ", 7);

        gchar *equals;

        if((equals = strchr(args[1], '=')))
            member->room = g_strdup(equals + 1);
        if(parts[6])
        {
            member->bio = pecker_bio_strdup(parts[6]);
            member->thumbnail = pecker_thumbnail_strdup(parts[6]);
            char *prefix_start = NULL;

            if(g_ascii_isdigit(parts[3][0]) && (prefix_start = strchr(parts[3], '|')))
                member->prefix = g_strdup(prefix_start + 1);
            else
                member->prefix = g_strdup(parts[3]);


            gchar *stats = pecker_stats_strdup(parts[6]);

            if(stats)
            {
                gchar **stat_parts = g_strsplit(stats, "|", 3);

                member->sex = stat_parts[0];
                member->age = stat_parts[1];
                member->location = stat_parts[2];
                g_free(stats);
            }

            nameslist->members = g_slist_prepend(nameslist->members, member);
        }
        g_strfreev(parts);

        pos = strrchr(args[1], '=');
        int val = 0;

        if(!pos)
            return;
        val = g_ascii_digit_value(*(++pos));
        if(val != nameslist->num_rooms)
        {
            purple_debug_misc("msgs", "*******NEXT ROOM******\n");
            const char *cmdargs[1] = { args[1] };
            pecker_cmd_names(pecker, NULL, NULL, cmdargs);
            nameslist->num_rooms = val;
        }
    }
    // Use the who msgs cross-referenced with the NAMES list to figure out 
    // 
    // 
    // who is who. Resolve conflicts.

}
*/

void
hammer_stop_cb(gpointer data)
{
    struct hammer_cb_data *hdata = (struct hammer_cb_data *) data;

    purple_debug_misc("pecker", "hammer stopped, dialog is %s\n", ((const char *) hdata->cancel_dialog));
    // This destroys the hammer data!
    purple_debug_misc("pecker", "Cancelling hammer: %s\n", hdata->room);
    // I'm not sure if the dialog data is freed. 
    // For now, I assume not. 
    // hdata->cancel_dialog=0;
    // The old key gets freed, so strdup it again
    g_hash_table_replace(hdata->pecker->hammers, g_strdup(hdata->room), NULL);
}

void
hammer_cb_data_destroy(struct hammer_cb_data *hdata)
{
    if(!hdata)
        return;
    if(hdata->cancel_dialog)
        purple_request_close(PURPLE_REQUEST_ACTION, hdata->cancel_dialog);
    if(hdata->room)
        g_free(hdata->room);
    g_free(hdata);
}

void
hammer_cb_no(gpointer data)
{
    hammer_cb_data_destroy(data);
}

void
hammer_cb_yes(gpointer data)
{
    struct hammer_cb_data *hdata = (struct hammer_cb_data *) data;
    char *room = g_strdup(hdata->room);
    const char *args[1] = { room };

    char *msg;

    msg = g_strdup_printf("Hammering into room %s", hdata->room);
    hdata->cancel_dialog =
        purple_request_action(hdata->pecker->account->gc, "Hammering...", msg, NULL, 0, NULL, hdata->room, NULL, hdata, 1,
                              ("Cancel"), hammer_stop_cb);
    g_hash_table_insert(hdata->pecker->hammers, g_strdup(hdata->room), hdata);
    pecker_cmd_join(hdata->pecker, NULL, NULL, args);
    if(msg)
        g_free(msg);
    if(room)
        g_free(room);
}

void
pecker_msg_chanfull(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    gchar *buf;
    const char *joinargs[1];

    if(!args || !args[1] || !gc)
        return;

    joinargs[0] = args[1];

    gpointer unused = NULL;
    gpointer data = NULL;
    gboolean hammering = g_hash_table_lookup_extended(pecker->hammers, args[1], &unused, &data);

    if(hammering && data)
    {
        // Add delay here?
        pecker_cmd_join(pecker, NULL, NULL, joinargs);
    }
    else if(hammering && !data)
    {                           // hammer was cancelled.
        purple_debug_misc("pecker", "HAMMER CANCELLED ON FULL MESSAGE\n");
        g_hash_table_remove(pecker->hammers, args[1]);
    }
    else
    {
        buf = g_strdup_printf("%s is full. Do you want to keep trying?", args[1]);
        struct hammer_cb_data *hdata = g_new0(struct hammer_cb_data, 1);

        hdata->pecker = pecker;
        hdata->room = g_strdup(args[1]);
        hdata->cancel_dialog = NULL;
#define _(x) x
        purple_request_yes_no(gc, "Room Full", "Room Full", buf, 0, NULL, NULL, NULL, hdata, hammer_cb_yes, hammer_cb_no);

        g_free(buf);
    }

}

void
pecker_msg_create_pay_only(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *buf;

    if(!args || !args[1] || !gc)
    {
        return;
    }
    buf = g_strdup_printf("%s", args[2]);
    purple_notify_error(gc, "Pay Only", "Pay Only", buf);
    /**
     * FIXME
     * by now the chatroom is already in the buddy list...need
     * to remove it or something
     */
    g_free(buf);
}

void
pecker_msg_pay_channel(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *buf;

    if(!args || !args[1] || !gc)
        return;

    buf = g_strdup_printf("The channel %s is for paying members only.", args[1]);
    purple_notify_error(gc, "Pay Only", "Pay Only", buf);
    g_free(buf);
}

void
pecker_msg_toomany_channels(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *buf;

    if(!args || !args[1] || !gc)
        return;

    buf =
        g_strdup_printf
        ("You have joined too many channels the maximum is (2). You cannot join channel %s. Part another channel first .",
         args[1]);
    purple_notify_error(gc, "Maximum ChannelsReached", "Maximum ChannelsReached", buf);
    g_free(buf);
}

void
pecker_msg_list_busy(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    char *buf;

    if(!args || !args[1] || !gc)
    {
        return;
    }
    buf = g_strdup_printf("%s", args[1]);
    purple_notify_error(gc, "Server Busy", "Server Busy", buf);
    // if (pecker->roomlist) {
    // purple_roomlist_cancel_get_list(pecker->roomlist);
    // }
    g_free(buf);
    /**
     * Can't get member created rooms right now.
     * This is our trigger to add the static rooms
     */
    build_roomlist_from_config(pecker->roomlist, pecker->confighash, pecker->roomlist_filter);
    if(pecker->roomlist_filter)
    {
        g_free(pecker->roomlist_filter);
        pecker->roomlist_filter = NULL;
    }
    return;

}

void
pecker_msg_richnames_list(struct pecker_conn *pecker, const char *name, const char *from, char **args)
{
    PurpleConnection *gc = purple_account_get_connection(pecker->account);
    PurpleConversation *convo;
    PurpleConvChatBuddyFlags flags = PURPLE_CBFLAGS_NONE;
    char *channel = args[1];
    char *nick = args[2];
    char *extra = args[4];

    if(!gc)
    {
        return;
    }

    gcom_nick_to_pecker(nick);
    purple_debug(PURPLE_DEBUG_INFO, "pecker", "pecker_msg_richnames_list() Channel: %s Nick: %s Extra: %s\n", channel, nick,
                 extra);

    convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, channel, pecker->account);

    char *bio = pecker_bio_strdup(extra);

    g_free(bio);

    pecker_buddy_status(pecker, nick, TRUE, extra, FALSE);

    if(convo == NULL)
    {
        purple_debug(PURPLE_DEBUG_ERROR, "pecker", "690 for %s failed\n", args[1]);
        return;
    }

    gint *entry = g_hash_table_lookup(pecker->entry_order, channel);

    g_return_if_fail(entry != NULL);

    flags = chat_pecking_order(extra);
    flags = include_chat_entry_order(flags, (*entry)--);

    purple_conv_chat_add_user(PURPLE_CONV_CHAT(convo), nick, NULL, flags, FALSE);

    /**
     * Make the ignore.png icon appear next to the nick.
     */
    PurpleConversationUiOps *ops = purple_conversation_get_ui_ops(convo);

    if(pecker_privacy_check(gc, nick))
    {
        purple_conv_chat_unignore(PURPLE_CONV_CHAT(convo), nick);
    }
    else
    {
        purple_conv_chat_ignore(PURPLE_CONV_CHAT(convo), nick);
    }
    ops->chat_update_user((convo), nick);
    pecker_update_channel_member(pecker, nick, extra);
}

/*
	* list[] is the spam_list, 
	* msg is the received message we are checking
	*/
int
pecker_msg_is_spam(char *msg)
{
    int i;
    int size = sizeof(spam_list) / sizeof(const char *) - 1;

    for (i = 0; i < size; i++)
        if(purple_strcasestr(msg, spam_list[i]) != 0)
            return 1;

    return 0;
}


/**
 * vim:tabstop=4:shiftwidth=4:expandtab:
 */
